home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / gs3.53 / pdf_main.ps < prev    next >
Text File  |  1996-01-10  |  12KB  |  399 lines

  1. %    Copyright (C) 1994, 1995 Aladdin Enterprises.  All rights reserved.
  2.  
  3. % pdf_main.ps
  4. % PDF file- and page-level operations.
  5.  
  6. % We do handle the following PDF 1.1 extensions:
  7. %
  8. %    - The Dest element of a link or outline entry can be a name,
  9. %    in which case it is looked up in the (optional) Dests dictionary
  10. %    that can appear as an element of the Catalog.
  11. %
  12. %    - The page identifier in a link Dest element can be null, meaning
  13. %    the same page as the link itself appears on.
  14.  
  15. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  16. .currentglobal true .setglobal
  17. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  18. pdfdict begin
  19.  
  20. % For simplicity, we use a single interpretation dictionary for all
  21. % PDF graphics execution, even though this is too liberal.
  22. /pdfopdict mark
  23.   objopdict { } forall
  24.   drawopdict { } forall
  25.   /endstream { exit } bind
  26.   (%%EOF) cvn { exit } bind        % for filters
  27. .dicttomark readonly def
  28.  
  29. % ======================== Main program ======================== %
  30.  
  31. end            % pdfdict
  32. userdict begin
  33.  
  34. /defaultfontname /Times-Roman def
  35.  
  36. % Make sure the registered encodings are loaded, so we don't run the risk
  37. % that some of the indices for their names will overflow the packed
  38. % representation.  (Yes, this is a hack.)
  39. SymbolEncoding pop
  40. DingbatsEncoding pop
  41.  
  42. % Redefine 'run' so it recognizes PDF files.
  43. systemdict begin
  44. /runps /run load def
  45. /run
  46.  { dup type /filetype ne { (r) file } if
  47.    dup read
  48.     { dup (%) 0 get eq
  49.        { pop dup =string readline pop
  50.      (PDF-) anchorsearch
  51.       { pop pop runpdf }
  52.       { pop cvx exec }
  53.      ifelse
  54.        }
  55.        { 2 copy unread pop cvx exec
  56.        }
  57.       ifelse
  58.     }
  59.     { closefile
  60.     }
  61.    ifelse
  62.  } bind odef
  63. /runpdf            % <file> runpdf -
  64.  { userdict begin
  65.    /PSFile where { pop PSFile (w) file /PSout exch def } if
  66.    /Page# null def
  67.    /Page null def
  68.    /PDFSave null def
  69.    GS_PDF_ProcSet begin
  70.    pdfdict begin
  71.    pdfopen begin
  72.    Trailer /Root oget /Pages oget /CropBox knownoget
  73.     { mark /CropBox 3 -1 roll /PAGES pdfmark
  74.     }
  75.    if
  76.    /FirstPage where { pop FirstPage } { 1 } ifelse
  77.    1
  78.    /LastPage where { pop LastPage } { pdfpagecount } ifelse
  79.    QUIET not
  80.     { (Processing pages ) print 2 index =only ( through ) print dup =only
  81.       (.\n) print flush
  82.     }
  83.    if
  84.     { dup /Page# exch store
  85.       QUIET not { (Page ) print dup == flush } if
  86.       [ (%%Page: ) 2 index ( ) 1 index #dsc
  87.       [ (GS_PDF_ProcSet begin) #dsc
  88.       pdfgetpage /Page exch store
  89.       save /PDFSave exch store
  90.       (before exec) VMDEBUG
  91.          Page pdfshowpage
  92.       (after exec) VMDEBUG
  93.       PDFSave restore
  94.       [ (end) #dsc
  95.     } for
  96.    currentdict pdfclose
  97.    end
  98.    end
  99.    end
  100.  } bind def
  101. % Rebind procedures that invoke 'run'.
  102. /runlibfile
  103.     { findlibfile dup pop
  104.        { exch pop run }
  105.        { /undefinedfilename signalerror }
  106.       ifelse
  107.     } bind def
  108. /.runlibfile /runlibfile load def
  109. end            % systemdict
  110.  
  111. end            % userdict
  112. pdfdict begin
  113.  
  114. % ======================== File parsing ======================== %
  115.  
  116. % Read the cross-reference and trailer sections.
  117.  
  118. /traileropdict mark
  119.   (<<) cvn { mark } bind
  120.   (>>) cvn /.dicttomark load
  121.   /[ { mark } bind        % ditto
  122.   /] /] load
  123.   /true true
  124.   /false false
  125.   /null null
  126.   /R { /resolveR cvx 3 packedarray cvx } bind    % see Objects below
  127.   /startxref /exit load
  128. .dicttomark readonly def
  129.  
  130. % Because of EOL conversion, lines with fixed contents might be followed
  131. % by one or more blanks.
  132. /lineeq            % <filestr> <conststr> lineeq <bool>
  133.  { anchorsearch
  134.     { pop { ( ) anchorsearch not { () eq exit } if pop } loop }
  135.     { pop false }
  136.    ifelse
  137.  } bind def
  138. /linene { lineeq not } bind def
  139.  
  140. % Read (mostly scan) the cross-reference table.
  141. /readxref        % <pos> readxref <trailerdict>
  142.  { PDFoffset add PDFfile exch setfileposition
  143.    PDFfile pdfstring readline pop
  144.    (xref) linene { /readxref cvx /syntaxerror signalerror } if
  145.         % Store the xref table entry position for each object.
  146.         % We only need to read the run headers, not every entry.
  147.     { PDFfile pdfstring readline pop
  148.       dup (trailer) lineeq { pop exit } if
  149.       token pop            % first object #
  150.       exch token pop        % entry count
  151.       exch pop exch
  152.             % Stack: count obj#
  153.       PDFfile fileposition 3 -1 roll
  154.        { Objects 2 index get null eq    % later update might have set it
  155.       { Objects 2 index 2 index cvx put }
  156.          if exch 1 add exch 20 add
  157.        }
  158.       repeat PDFfile exch setfileposition pop
  159.     } loop
  160.    PDFfile traileropdict .pdfrun
  161.  } bind def
  162.  
  163. % Open a PDF file and read the trailer and cross-reference.
  164. /pdfopen        % <file> pdfopen <dict>
  165.  { 10 dict begin
  166.    cvlit /PDFfile exch def
  167.    /PDFsource PDFfile def
  168.    PDFfile dup 0 setfileposition pdfstring readstring 
  169.    not {/pdfopen cvx /syntaxerror signalerror} if
  170.    (%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
  171.    length /PDFoffset exch def pop pop
  172.    PDFfile dup dup 0 setfileposition bytesavailable 
  173.     % Scan backwards over trailing control-character garbage
  174.     % (nulls, ^Zs, EOLs).
  175.     { 1 sub 2 copy setfileposition 1 index read pop
  176.       32 ge {exit} if
  177.     } loop 1 sub setfileposition
  178.    prevline (%%EOF) linene { /pdfopen cvx /syntaxerror signalerror } if
  179.    PDFfile exch setfileposition
  180.    prevline cvi        % xref start position
  181.    exch PDFfile exch setfileposition
  182.    prevline (startxref) linene { /pdfopen cvx /syntaxerror signalerror } if
  183.     % Scan backwards for the start of the trailer,
  184.     % since we have to read the trailer before the first xref section.
  185.     { PDFfile exch setfileposition
  186.       prevline (trailer) lineeq { exit } if
  187.     }
  188.    loop pop PDFfile traileropdict .pdfrun
  189.         % Stack: xrefpos trailerdict
  190.    /Trailer exch def
  191.    Trailer /Size get
  192.    /Objects 1 index array def
  193.    /Generations exch string def
  194.     % Read the last cross-reference table.
  195.    readxref pop
  196.     % Read any previous cross-reference tables.
  197.    Trailer { /Prev .knownget not { exit } if readxref } loop
  198.     % Create and initialize some caches.
  199.    /PageCount pdfpagecount def
  200.    /PageNumbers PageCount dict def
  201.    /PageIndex PageCount array def
  202.     % Write the DSC header if appropriate.
  203.    [ (%!PS-Adobe-1.0) #dsc
  204.    [ (%%Pages: ) pdfpagecount #dsc
  205.    [ (%%EndComments) #dsc
  206.    [ (%%BeginProlog) #dsc
  207.    [ (% The following copyright notice applies only to the Prolog section:) #dsc
  208.    (gs_pdf.ps) #dscfile
  209.    [ (%%EndProlog) #dsc
  210.     % Copy bookmarks (outline) to the output.
  211.    #?
  212.     { Trailer /Root oget /Outlines knownoget
  213.        { /First knownoget
  214.       { { dup writeoutline /Next knownoget not { exit } if } loop }
  215.      if
  216.        }
  217.       if
  218.     }
  219.    if   
  220.    currentdict end
  221.  } bind def
  222.  
  223. % Write the outline structure for a file.  Uses linkdest (below).
  224. /writeoutline        % <outlinedict> writeoutline -
  225.  { mark
  226.    0 2 index /First knownoget
  227.     { { exch 1 add exch /Next knownoget not { exit } if } loop }
  228.    if
  229.         % stack: dict mark count
  230.    dup 0 eq
  231.     { pop 1 index
  232.     }
  233.     { 2 index /Count knownoget { 0 lt { neg } if } if
  234.       /Count exch 3 index
  235.     }
  236.    ifelse linkdest /Title oget /Title exch /OUT pdfmark
  237.    /First knownoget
  238.     { { dup writeoutline /Next knownoget not { exit } if } loop }
  239.    if
  240.  } bind def
  241.  
  242. % Close a PDF file.
  243. /pdfclose        % <dict> pdfclose -
  244.  { begin
  245.    /PSout where { pop [ (%%Trailer) #dsc PSout closefile } if
  246.    PDFfile closefile
  247.    end
  248.  } bind def
  249.  
  250. % ======================== Page accessing ======================== %
  251.  
  252. % Get a (possibly inherited) attribute of a page.
  253. /pget            % <pagedict> <key> pget <value> -true-
  254.             % <pagedict> <key> pget -false-
  255.  { 2 copy knownoget
  256.     { exch pop exch pop true
  257.     }
  258.     { exch /Parent knownoget
  259.        { exch pget }
  260.        { pop false }
  261.       ifelse
  262.     }
  263.    ifelse
  264.  } bind def
  265.  
  266. % Get the total number of pages in the document.
  267. /pdfpagecount        % - pdfpagecount <int>
  268.  { Trailer /Root oget /Pages oget /Count oget
  269.  } bind def
  270.  
  271. % Find the N'th page of the document by iterating through the Pages tree.
  272. % The first page is numbered 1.
  273. /pdffindpage        % <int> pdffindpage <pagedict>
  274.  { dup Trailer /Root oget /Pages oget
  275.     {        % We should be able to tell when we reach a leaf
  276.         % by finding a Type unequal to /Pages.  Unfortunately,
  277.         % some files distributed by Adobe lack the Type key
  278.         % in some of the Pages nodes!  Instead, we check for Kids.
  279.       dup /Kids knownoget not { exit } if
  280.       exch pop null
  281.       0 1 3 index length 1 sub
  282.        { 2 index exch oget
  283.      dup /Kids known { dup /Count oget } { 1 } ifelse
  284.         % Stack: index kids null node count
  285.      dup 5 index ge { pop exch pop exit } if
  286.      5 -1 roll exch sub 4 1 roll pop
  287.        }
  288.       for exch pop
  289.       dup null eq { pop pop 1 null exit } if
  290.     }
  291.    loop
  292.         % Stack: index countleft node
  293.    1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
  294.    exch pop
  295.    PageIndex 2 index 1 sub 2 index put
  296.    PageNumbers 1 index 3 index put
  297.    exch pop
  298.  } bind def
  299.  
  300. % Find the N'th page of the document.
  301. % The first page is numbered 1.
  302. /pdfgetpage        % <int> pdfgetpage <pagedict>
  303.  { PageIndex 1 index 1 sub get dup null ne
  304.     { exch pop }
  305.     { pop pdffindpage }
  306.    ifelse
  307.  } bind def
  308.  
  309. % Find the page number of a page object (inverse of pdfgetpage).
  310. /pdfpagenumber        % <pagedict> pdfpagenumber <int>
  311.  {    % We use the simplest and stupidest of all possible algorithms....
  312.    PageNumbers 1 index .knownget
  313.     { exch pop
  314.     }
  315.     { 1 1 PageCount 1 add    % will give a rangecheck if not found
  316.        { dup pdfgetpage oforce 2 index eq { exit } if pop
  317.        }
  318.       for exch pop
  319.     }
  320.    ifelse
  321.  } bind def
  322.  
  323. % Display a given page.
  324. /boxrect        % [<llx> <lly> <urx> <ury>] boxrect <x> <y> <w> <h>
  325.  { aload pop exch 3 index sub exch 2 index sub
  326.  } bind def
  327. /linkdest        % <link|outline> linkdest
  328.             %   ([/Page <n>] /View <view> | ) <link|outline>
  329.  { dup /Dest knownoget
  330.     {        % Check for a name, to be looked up in Dests.
  331.       dup type /nametype eq
  332.        { Trailer /Root oget /Dests oget exch oget /D get }
  333.       if
  334.       dup 0 oget
  335.       dup null eq
  336.        { pop }
  337.        { pdfpagenumber 1 add /Page exch 4 -2 roll }
  338.       ifelse
  339.       dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
  340.     }
  341.    if
  342.  } bind def
  343. /annottypes 5 dict dup begin
  344.   /Text
  345.     { mark exch
  346.        { /Rect /Open /Contents }
  347.        { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  348.       forall pop /ANN pdfmark
  349.     } bind def
  350.   /Link
  351.     { mark exch
  352.        { /Rect /Border }
  353.        { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  354.       forall linkdest pop /LNK pdfmark
  355.     } bind def
  356. end def
  357. /pdfshowpage        % <pagedict> pdfshowpage -
  358.  { dup /Contents knownoget not { 0 array } if
  359.    dup type /arraytype ne { 1 array astore } if
  360.    gsave
  361.    1 index /MediaBox pget
  362.     {            % Set the page size.
  363.       boxrect statusdict /.setpagesize get exec
  364.       exch neg exch neg translate
  365.     }
  366.     { initmatrix initclip
  367.     }
  368.    ifelse
  369.    1 index /CropBox pget
  370.     { boxrect rectclip
  371.       1 index /CropBox knownoget { mark /CropBox 3 -1 roll /PAGE pdfmark } if
  372.     }
  373.    if
  374.    1 index /Rotate pget
  375.     { clippath pathbbox newpath
  376.       3 -1 roll add 2 div 3 1 roll add 2 div exch
  377.       2 copy translate 3 -1 roll neg rotate
  378.       exch neg exch neg translate
  379.     }
  380.    if
  381.     % Copy annotations and links.
  382.    1 index /Annots knownoget
  383.     { 0 1 2 index length 1 sub
  384.        { 1 index exch oget
  385.          dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
  386.        }
  387.       for pop
  388.     }
  389.    if
  390.    exch pop
  391.    matrix currentmatrix /beginpage 0 # setmatrix
  392.     { oforce false resolvestream pdfopdict .pdfrun } forall
  393.    /endpage 0 #
  394.    grestore
  395.  } bind def
  396.  
  397. end            % pdfdict
  398. .setglobal
  399.